<?php
declare(strict_types=1);

namespace App\Model;

use App\Helper\TreeHelper;
use Carbon\Carbon;
use Hyperf\Utils\ApplicationContext;
use Psr\SimpleCache\CacheInterface;
use Psr\SimpleCache\InvalidArgumentException;

/**
 * @property int $id
 * @property int $parent_id
 * @property string $name
 * @property string $name_id
 * @property int $sort_number
 * @property Carbon $created_at
 * @property Carbon $updated_at
 */
class ContentMenu extends MyBaseModel
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'content_menu';
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [];
    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = ['id' => 'integer', 'parent_id' => 'integer', 'sort_number' => 'integer', 'created_at' => 'datetime', 'updated_at' => 'datetime'];

    public static function getAllSelectOptions(array $withoutNameIds = []): array
    {
        return (static::getTreeFromCache($withoutNameIds))->getSelectOptions();
    }

    public static function getTreeFromCache(array $withoutNameIds = []): TreeHelper
    {
        $key = 'menu_tree_data:' . md5(serialize($withoutNameIds));
        try {
            $cache = ApplicationContext::getContainer()->get(CacheInterface::class);
            $treeData = $cache->get($key);
            if (is_array($treeData)) {
                return new TreeHelper($treeData);
            }
            $tree = static::getTree($withoutNameIds);
            $cache->set($key, $tree->data, 1800);
            return $tree;
        } catch (InvalidArgumentException $e) {
            return static::getTree($withoutNameIds);
        }
    }

    public static function getTree(array $withoutNameIds = []): TreeHelper
    {
        $data = [];
        $query = static::query()->select(['id', 'parent_id', 'name']);
        if ($withoutNameIds) {
            $query->whereNotIn('name_id', $withoutNameIds);
        }
        $models = $query->orderByDesc('sort_number')->getModels();
        /* @var ContentMenu $model */
        foreach ($models as $model) {
            array_push($data, [
                'id' => $model->id,
                'parent_id' => $model->parent_id,
                'name' => $model->name,
            ]);
        }
        return new TreeHelper($data);
    }

    public static function getIdByNameId(string $nameId): ?int
    {
        if (!$nameId) {
            return null;
        }
        $query = static::query()->select(['id'])->where('name_id', '=', $nameId)->limit(1);
        $ids = static::getIdsByBuilderFromCache($query);
        return $ids[0] ?? null;
    }

    public static function canBeParentId(int $parentIdToBeChecked, int $id): bool
    {
        if ($id <= 0 || $parentIdToBeChecked < 0) {
            return false;
        }
        if ($parentIdToBeChecked == 0) {
            return true;
        }
        if ($parentIdToBeChecked == $id) {
            return false;
        }
        $parents = self::getFullParent($parentIdToBeChecked);
        if (is_null($parents)) {
            return false;
        }
        foreach ($parents as $parent) {
            if ($parent['id'] == $id) {
                return false;
            }
        }
        return true;
    }

    public static function getFullParent(int $parentId = 0): ?array
    {
        if ($parentId == 0) {
            return [['id' => 0, 'name' => '根']];
        }
        $model = self::find($parentId);
        if (!$model) {
            return null;
        }
        $data = self::getFullParent($model->parent_id);
        array_push($data, [
            'id' => $model->id,
            'name' => $model->name,
        ]);
        return $data;
    }
}
